/*
 * Project: a2
 * Copyright (C) 2008 ralfoide gmail com,
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.alfray.a2.engine;

import android.view.KeyEvent;
import android.view.MotionEvent;

import com.alfray.a2.gameplay.GameState;

/**
 * Adapts android.View UI events for board selection, that is
 * transforms touch, trackpad or keyboard events into a board cell
 * selection and activation.
 */
public class UIEventAdapter {

    private final GameState mGameState;
    private int mCellPx = 1;
    private int mCellPy = 1;
    private final IEventProcessor mProcessor;

    public interface IEventProcessor {
        public void onCursorMoved(int bx, int by);
        public void onCursorMovedDelta(int bx, int by);
        public void onActivate();
        public long getTouchDelayMs();
    }

    public UIEventAdapter(GameState gameState, IEventProcessor processor) {
        mGameState = gameState;
        mProcessor = processor;
    }

    /**
     * Called when the surface view is created or resized.
     * The view size is used to compute the cell size in pxels.
     */
    public void onWindowResized(int w, int h) {
        mCellPx = w / mGameState.mBoardBx;
        mCellPy = h / mGameState.mBoardBy;
    }

    /**
     * Implements IUiEventListener.onTouchEvent to process a touch event.
     * <p/>
     * If the motion event is an action move or down, it gets the cell
     * touched (if valid) and triggers onCursorMoved accordingly.
     * Action up activates the selection.
     */
    public boolean onTouchEvent(MotionEvent event) {
        int sx = mGameState.mBoardBx;
        int sy = mGameState.mBoardBy;
        int bx, by;
        boolean pause = false;

        switch(event.getAction()) {
        case MotionEvent.ACTION_MOVE:
        case MotionEvent.ACTION_DOWN:
            bx = (int) (event.getX() / mCellPx);
            by = (int) (event.getY() / mCellPy);

            // Note: GL has its coordinate going X towards right and Y
            // towards top whereas the 2d graphics use Y towards bottom
            // so we invert Y here.

            mProcessor.onCursorMoved(bx, sy - 1 - by);
            pause = true;
            break;

        case MotionEvent.ACTION_UP:
            bx = (int) (event.getX() / mCellPx);
            by = (int) (event.getY() / mCellPy);
            if (bx >= 0 && by >= 0 && bx < sx && by < sy) {
                mProcessor.onActivate();
            }
            break;
        }

        if (pause) {
            try {
                long delay = mProcessor.getTouchDelayMs();
                if (delay > 0) Thread.sleep(delay);
            } catch (InterruptedException e) {
                // ignore
            }
        }

        return true;
    }

    /**
     * Implements IUiEventListener.onTouchEvent to process a trackball event.
     * <p/>
     * For a move, it gets the delta and triggers onCursorMovedDelta accordingly.
     * Action up activates the selection.
     */
    public boolean onTrackballEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_MOVE) {
            float dx = event.getX();
            dx = Math.signum(dx);

            // Note: GL has its coordinate going X towards right and Y
            // towards top whereas the 2d graphics use Y towards bottom
            // so we invert Y here.

            float dy = -1 * event.getY();
            dy = Math.signum(dy);

            mProcessor.onCursorMovedDelta((int) dx, (int) dy);
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            mProcessor.onActivate();
        }
        return false;
    }

    /**
     * Implements view.Callback.onKeyUp to process a d-pad event.
     * <p/>
     * For a move, it gets the delta and triggers onCursorMovedDelta accordingly.
     * Action up activates the selection.
     */
    public boolean onKeyUp(int code, KeyEvent event) {
        // Note: GL has its coordinate going X towards right and Y
        // towards top whereas the 2d graphics use Y towards bottom
        // so we invert Y here.

        switch(code) {
            case KeyEvent.KEYCODE_DPAD_UP:
                mProcessor.onCursorMovedDelta( 0,  1);
                return true;
            case KeyEvent.KEYCODE_DPAD_DOWN:
                mProcessor.onCursorMovedDelta( 0, -1);
                return true;
            case KeyEvent.KEYCODE_DPAD_LEFT:
                mProcessor.onCursorMovedDelta(-1,  0);
                return true;
            case KeyEvent.KEYCODE_DPAD_RIGHT:
                mProcessor.onCursorMovedDelta( 1,  0);
                return true;
            case KeyEvent.KEYCODE_DPAD_CENTER:
            case KeyEvent.KEYCODE_ENTER:
                mProcessor.onActivate();
                return true;
        }
        return false;
    }

}
